package com.kefa.lock;

import static java.lang.System.arraycopy;

import android.os.SystemClock;

import com.lyn.serialPort.SerialPortManager;

import java.io.FileInputStream;

public class LockManager {

    private static class LockAddressTypeClass {
        private static LockManager instance = new LockManager();
    }

    public static LockManager getInstance() {
        return LockAddressTypeClass.instance;
    }

    //查询锁控板单个通道状态
    public static byte CMD_QUERY_STATE = (byte) 0x02;
    //查询锁控板所有通道状态
    public static byte CMD_QUERY_ALL_STATE = (byte) 0x0A;
    public static byte CMD_ON = (byte) 0x04;//开锁

    private SerialPortManager serialPortManager;


    /**
     * 波特率
     */
    private static final int BAUD_RATE = 9600;

    public boolean initialize(String portName) {
        if (serialPortManager == null) {
            serialPortManager = new SerialPortManager();
        }
        boolean openSerialPort = serialPortManager.openSerialPort(portName, BAUD_RATE);
        LogUtils.i("打开串口状态:" + openSerialPort);
        return openSerialPort;
    }


    /**
     * 关闭串口
     */
    public void close() {
        if (serialPortManager == null) return;
        serialPortManager = null;
        serialPortManager.closeSerialPort();

    }

    /**
     * 开锁
     *
     * @param lockAddress
     * @param lockNumber
     */
    public void openLock(int lockAddress, int lockNumber) {
        LogUtils.i("lockAddress:" + lockAddress + "lockNumber:" + lockNumber);
        if (serialPortManager == null) return;
        byte[] lockNumberData = new byte[1];
        lockNumberData[0] = (byte) lockNumber;
        sendCommand(CMD_ON, (byte) lockAddress, lockNumberData, false);
    }

    /**
     * 查询所有锁状态
     *
     * @param lockAddress
     * @return
     */
    public int[] queryAllLockState(int lockAddress) {
        try {
            byte[] bytes = sendCommand(CMD_QUERY_ALL_STATE, (byte) lockAddress, null, true);
            if (bytes != null) {
                int length = bytes.length;
                LogUtils.i("数据长度:" + length);
                if (length <= 8) {
                    return null;
                }
                if (length == 21) {
                    byte[] resultData = new byte[12];
                    System.arraycopy(bytes, 8, resultData, 0, resultData.length);
                    int[] lockStateArray = new int[resultData.length];
                    int lockStateArrayLength = resultData.length;
                    for (int i = 0; i < lockStateArrayLength; i++) {
                        lockStateArray[i] = resultData[i];
                    }
                    return lockStateArray;
                } else {
                    byte[] resultData = new byte[24];
                    System.arraycopy(bytes, 8, resultData, 0, resultData.length);
                    int[] lockStateArray = new int[resultData.length];
                    int lockStateArrayLength = resultData.length;
                    for (int i = 0; i < lockStateArrayLength; i++) {
                        lockStateArray[i] = resultData[i];
                    }
                    return lockStateArray;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        return null;
    }

    /**
     * 查询锁状态
     *
     * @param lockAddress
     * @param lockNumber
     * @return
     * @throws Exception
     */
    public int queryLockState(int lockAddress, int lockNumber) throws Exception {
        int[] ints = queryAllLockState(lockAddress);
        if (ints == null) {
            throw new Exception("查询失败!");
        }
        if (lockNumber == 0) {
            throw new Exception("查询失败");
        }
        return ints[lockNumber - 1];
    }


    /**
     * 旧协议
     *
     * @param cmd
     * @param address
     * @param param
     */
    public byte[] sendCommand(byte cmd, byte address, byte[] param, boolean isSync) {
        byte[] sendData = null;
        if (param != null) {
            sendData = new byte[param.length + 9];
        } else {
            sendData = new byte[9];
        }
        sendData[0] = (byte) 0x5A;//帧头1：固定为0x5A
        sendData[1] = (byte) 0x5A;//帧头2：固定为0x5A
        sendData[2] = (byte) 0x00;//源地址：主机固定为0x00
        sendData[3] = address;//目的地址0-31
        sendData[4] = (byte) 0x00;//包序号：主机可以固定0x00
        sendData[5] = cmd;//命令
        sendData[6] = (byte) 0x00;//结果：主机固定为0x00
        if (param != null) {
            sendData[7] = (byte) param.length;//数据长度：表示下面数据字段的长度。
            arraycopy(param, 0, sendData, 8, param.length);
            for (int i = 2; i < param.length + 8; i++) {
                sendData[param.length + 8] ^= sendData[i];//校验：从源地址到数据字段最后一个字节的异或校验。
            }
        } else {
            sendData[7] = (byte) 0;
            for (int i = 2; i < 8; i++) {
                sendData[8] ^= sendData[i];//校验：从源地址到数据字段最后一个字节的异或校验。
            }
        }
        if (isSync) {
            return syncSendData(sendData, 1000l);
        } else {
            sendData(sendData);
        }
        return null;
    }

    /**
     * 发送串口数据
     *
     * @param data
     */
    public void sendData(byte[] data) {
        if (serialPortManager == null) return;
        boolean sendData = serialPortManager.sendData(data);
        if (sendData) {
            LogUtils.i("发送串口数据成功");
        } else {
            LogUtils.i("发送串口数据失败");
        }
    }

    /**
     * 同步发送串口数据
     *
     * @param data
     * @param intervalTime
     * @return
     */
    public byte[] syncSendData(byte[] data, long intervalTime) {
        try {
            if (serialPortManager == null) return null;
            sendData(data);
            FileInputStream inputStream = serialPortManager.getInputStream();
            Long time = System.currentTimeMillis();
            //暂存每次返回数据长度，不变的时候为读取完数据
            int receiveLength = 0;
            while (System.currentTimeMillis() - time < intervalTime) {
                int available = inputStream.available();
                if (available > 0 && available == receiveLength) {
                    byte[] returnData = new byte[available];
                    inputStream.read(returnData);
                    return returnData;
                } else {
                    receiveLength = available;
                }
                SystemClock.sleep(10);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }


}
